package com.uinnova.product.eam.service.handler;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.binary.core.exception.BinaryException;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.google.common.collect.Lists;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.model.es.EamCategory;
import com.uinnova.product.eam.model.bm.PushParams;
import com.uinnova.product.eam.model.bm.ReleaseValidResponse;
import com.uinnova.product.eam.model.diagram.DiagramNodeJson;
import com.uinnova.product.eam.model.dm.bean.DataModelEntityNodeVo;
import com.uinnova.product.eam.service.EamCategorySvc;
import com.uinnova.product.eam.service.ICISwitchSvc;
import com.uinnova.product.eam.service.es.IamsESCIHistoryDesignSvc;
import com.uinnova.product.eam.service.es.IamsESCIRltInfoHistoryDesignSvc;
import com.uinnova.product.eam.service.utils.DataModelDiagramUtil;
import com.uinnova.product.vmdb.comm.bean.CIState;
import com.uinnova.product.vmdb.comm.model.ci.CCcCiClass;
import com.uinnova.product.vmdb.comm.model.ci.CcCi;
import com.uinnova.product.vmdb.comm.model.ci.CcCiAttrDef;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uinnova.project.api.diagram.v2.client.ESDiagramApiClient;
import com.uinnova.project.base.diagram.comm.model.ESDiagram;
import com.uinnova.project.base.diagram.comm.model.ESDiagramLink;
import com.uinnova.project.base.diagram.comm.model.ESDiagramNode;
import com.uinnova.project.db.eam.ESDiagramLinkDao;
import com.uinnova.project.db.eam.ESDiagramNodeDao;
import com.uino.api.client.cmdb.ICIClassApiSvc;
import com.uino.bean.cmdb.base.ESCIInfo;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.cmdb.query.ESCISearchBean;
import com.uino.util.sys.CheckAttrUtil;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service
public class PushFacadeService {

    @Resource
    ESDiagramApiClient diagramApiClient;
    @Resource
    ICISwitchSvc ciSwitchSvc;
    @Resource
    EamCategorySvc diagramCategorySvc;
    @Resource
    ICIClassApiSvc ciClassApiSvc;
    @Resource
    ESDiagramNodeDao esDiagramNodeDao;
    @Resource
    ESDiagramLinkDao esDiagramLinkDao;
    @Resource
    IamsESCIHistoryDesignSvc iamsESCIHistoryDesignSvc;
    @Resource
    IamsESCIRltInfoHistoryDesignSvc iamsESCIRltInfoHistoryDesignSvc;

    public ReleaseValidResponse checkDiagram(PushParams params) {
        List<String> diagramIds = params.getDiagramIds();
        String ownerCode = params.getOwnerCode();
        ReleaseValidResponse response = new ReleaseValidResponse();
        Map<Long, String> diagramNameMap = new HashMap<>(16);
        Map<String, Long> diagramIdMap = new HashMap<>(16);
        List<Long> diagramIdList = new ArrayList<>();
        Set<String> releaseDiagramIds = new HashSet<>();
        for (ESDiagram each : params.getDiagramList()) {
            if(BinaryUtils.isEmpty(each.getLocalVersion())){
                each.setLocalVersion(0);
            }
            if(BinaryUtils.isEmpty(each.getReleaseVersion())){
                each.setReleaseVersion(0);
            }
            if(!BinaryUtils.isEmpty(each.getReleaseDiagramId())){
                releaseDiagramIds.add(each.getReleaseDiagramId());
            }
            diagramNameMap.put(each.getId(), each.getName());
            diagramIdMap.put(each.getDEnergy(), each.getId());
            diagramIdList.add(each.getId());
        }
        List<EamCategory> categories = diagramCategorySvc.selectByDiagramIdList(diagramIds, ownerCode, LibType.PRIVATE);
        List<ESDiagramNode> nodes = diagramApiClient.selectNodeByDiagramIds(diagramIdList);

        ReleaseValidResponse.CiData checkData = checkCiData(categories, nodes, diagramNameMap, diagramIdMap, ownerCode);
        if(!BinaryUtils.isEmpty(checkData)){
            response.setResultCode(0);
            response.setValidType(ReleaseValidResponse.ValidType.CI_DATA);
            response.setResponseData(checkData);
            return response;
        }
        List<String> freeCiCodes = categories.stream().map(EamCategory::getCiCode).distinct().collect(Collectors.toList());
        Map<String, String> assetMapper = findMapperInDiagramNode(diagramIdList, freeCiCodes);
        Map<String, String> tempDiagramMapper = new HashMap<>(16);
        if (!BinaryUtils.isEmpty(assetMapper)) {
            List<EamCategory> designCategories = diagramCategorySvc.selectByModelId(params.getModelId(), LibType.DESIGN, params.getOwnerCode());
            List<EamCategory> privateCategories = diagramCategorySvc.selectByModelId(params.getModelId(), LibType.PRIVATE, params.getOwnerCode());
            Map<String, EamCategory> assetDesignCategoryMap = designCategories.stream().collect(Collectors.toMap(EamCategory::getCiCode, each -> each, (k1, k2) -> k1));

            for (EamCategory privateCategory : privateCategories) {
                if (BinaryUtils.isEmpty(privateCategory.getDiagramId())) {
                    continue;
                }
                String pAssetCode = privateCategory.getCiCode();
                EamCategory matchDesignCategory = assetDesignCategoryMap.get(pAssetCode);
                if (null == matchDesignCategory) {
                    String dAssetCode = assetMapper.get(pAssetCode);
                    if (BinaryUtils.isEmpty(dAssetCode)) {
                        continue;
                    }
                    matchDesignCategory = assetDesignCategoryMap.get(dAssetCode);
                }
                if (BinaryUtils.isEmpty(matchDesignCategory) || BinaryUtils.isEmpty(matchDesignCategory.getDiagramId())) {
                    continue;
                }
                if (!releaseDiagramIds.contains(matchDesignCategory.getDiagramId())) {
                    releaseDiagramIds.add(matchDesignCategory.getDiagramId());
                    tempDiagramMapper.put(privateCategory.getDiagramId(), matchDesignCategory.getDiagramId());
                }
            }
        }
        if (!BinaryUtils.isEmpty(releaseDiagramIds)) {
            List<ReleaseValidResponse.DiagramVersionInfo> versionInfoList = new ArrayList<>();
            //设计库视图信息
            List<ESDiagram> esDiagrams = diagramApiClient.selectByIds(releaseDiagramIds, null, Collections.singletonList(1));
            Map<String, ESDiagram> diagramMap = esDiagrams.stream().collect(Collectors.toMap(ESDiagram::getDEnergy, each -> each, (k1, k2) -> k1));
            for (ESDiagram esDiagram : params.getDiagramList()) {
                ESDiagram releaseDiagram;
                if (BinaryUtils.isEmpty(esDiagram.getReleaseDiagramId())) {
                    String releaseDiagramId = tempDiagramMapper.get(esDiagram.getDEnergy());
                    if (BinaryUtils.isEmpty(releaseDiagramId)) {
                        continue;
                    }
                    releaseDiagram = diagramMap.get(releaseDiagramId);
                } else {
                    releaseDiagram = diagramMap.get(esDiagram.getReleaseDiagramId());
                }
                if (BinaryUtils.isEmpty(releaseDiagram)) {
                    continue;
                }
                if (esDiagram.getReleaseVersion() < releaseDiagram.getReleaseVersion()) {
                    //视图版本不正确
                    ReleaseValidResponse.DiagramVersionInfo info = new ReleaseValidResponse.DiagramVersionInfo();
                    info.setDiagramName(esDiagram.getName());
                    info.setPrivateVersion("v" + esDiagram.getReleaseVersion());
                    info.setDesignVersion("v" + releaseDiagram.getReleaseVersion());
                    versionInfoList.add(info);
                }
            }
            if (!BinaryUtils.isEmpty(versionInfoList)) {
                ReleaseValidResponse.DiagramVersionData diagramVersionData = new ReleaseValidResponse.DiagramVersionData();
                diagramVersionData.setVersionData(versionInfoList);
                response.setResultCode(0);
                response.setValidType(ReleaseValidResponse.ValidType.DIAGRAM_VERSION);
                response.setResponseData(diagramVersionData);
            }
        }
        return response;
    }

    /**
     * 校验ci对象信息完整性
     * @param catalogs 目录
     * @param nodes 视图节点集合
     * @param nameMap 视图id-视图名称map
     * @param ownerCode 当前用户
     * @return 校验结果
     */
    private ReleaseValidResponse.CiData checkCiData(List<EamCategory> catalogs,List<ESDiagramNode> nodes, Map<Long, String> nameMap, Map<String, Long> diagramIdMap, String ownerCode){
        Map<Long, List<ESDiagramNode>> nodeGroup = nodes.stream().collect(Collectors.groupingBy(ESDiagramNode::getDiagramId));
        Map<Long, Set<String>> ciCodeMap = new HashMap<>(16);
        Set<String> ciCodes = new HashSet<>();
        for (Long each : nodeGroup.keySet()) {
            List<ESDiagramNode> nodeList = nodeGroup.get(each);
            Set<String> nodeCiCode = DataModelDiagramUtil.getNodeCiCode(nodeList);
            ciCodes.addAll(nodeCiCode);
            ciCodeMap.put(each, nodeCiCode);
        }

        Map<Long, Integer> diagramIdMapLvl = MapUtil.newHashMap();
        for (EamCategory catalog : catalogs) {
            diagramIdMapLvl.put(diagramIdMap.get(catalog.getDiagramId()), catalog.getDirLvl());
            ciCodes.add(catalog.getCiCode());
        }
        List<Long> diagramIdSort = new ArrayList<>(ciCodeMap.keySet());
        diagramIdSort.sort((o1, o2) -> {
            if (BinaryUtils.isEmpty(diagramIdMapLvl) || BinaryUtils.isEmpty(diagramIdMapLvl.get(o1)) || BinaryUtils.isEmpty(diagramIdMapLvl.get(o2))) {
                return 0;
            }
            return diagramIdMapLvl.get(o1) - diagramIdMapLvl.get(o2);
        });

        List<ESCIInfo> ciList = ciSwitchSvc.getCiByCodes(new ArrayList<>(ciCodes), ownerCode, LibType.PRIVATE);
        if (BinaryUtils.isEmpty(ciList)) {
            return null;
        }
        Map<String, ESCIInfo> ciMap = ciList.stream().collect(Collectors.toMap(CcCi::getCiCode, each -> each, (k1, k2) -> k2));
        Long[] classIds = ciList.stream().map(ESCIInfo::getClassId).distinct().toArray(Long[]::new);
        CCcCiClass cdt = new CCcCiClass();
        cdt.setIds(classIds);
        List<CcCiClassInfo> ciClassList = ciClassApiSvc.queryClassByCdt(cdt);
        Map<Long, CcCiClassInfo> classMap = ciClassList.stream().collect(Collectors.toMap(each -> each.getCiClass().getId(), each -> each, (k1, k2) -> k2));
        //对象校验CI
        List<ReleaseValidResponse.CiInfo> ciInfoList = new ArrayList<>();
        ArrayList<String> errCiCodes = new ArrayList<>();
        for (Long diagramId : diagramIdSort) {
            List<ESDiagramNode> nodeList = nodeGroup.get(diagramId);
            if(BinaryUtils.isEmpty(nodeList)){
                continue;
            }
            List<ReleaseValidResponse.CiAttrInfo> checkData = new ArrayList<>();
            for (ESDiagramNode node : nodeList) {
                if(BinaryUtils.isEmpty(node.getCiCode())){
                    continue;
                }
                ESCIInfo ciInfo = ciMap.get(node.getCiCode());
                if(BinaryUtils.isEmpty(ciInfo)){
                    continue;
                }
                ReleaseValidResponse.CiAttrInfo ciAttrInfo = validCiAttr(ciInfo, ciMap, classMap, null);
                if(ciAttrInfo != null){
                    checkData.add(ciAttrInfo);
                }
                if(BinaryUtils.isEmpty(node.getNodeJson())){
                    continue;
                }
                //添加处理ER图实体属性节点情况
                DiagramNodeJson nodeJson = JSON.parseObject(node.getNodeJson(), DiagramNodeJson.class);
                if(BinaryUtils.isEmpty(nodeJson.getItems())){
                    continue;
                }
                String entityName = extractMessageByRegular(ciInfo.getCiLabel()).get(0).replaceAll("\"", "");
                for (DataModelEntityNodeVo item : nodeJson.getItems()) {
                    if(BinaryUtils.isEmpty(item.getCiCode())){
                        continue;
                    }
                    ESCIInfo attr = ciMap.get(item.getCiCode());
                    if(BinaryUtils.isEmpty(attr)){
                        continue;
                    }
                    ReleaseValidResponse.CiAttrInfo ciItemInfo = validCiAttr(attr, ciMap, classMap, entityName);
                    if(ciItemInfo != null){
                        checkData.add(ciItemInfo);
                    }
                }
            }
            if (BinaryUtils.isEmpty(checkData)) {
                continue;
            }
            //每张视图对应校验信息
            ReleaseValidResponse.CiInfo ciInfo = new ReleaseValidResponse.CiInfo();
            ciInfo.setCheckData(checkData);
            ciInfo.setDiagramName(nameMap.get(diagramId));
            ciInfoList.add(ciInfo);
        }
        if(BinaryUtils.isEmpty(ciInfoList)){
            return null;
        }
        ReleaseValidResponse.CiData ciData = new ReleaseValidResponse.CiData();
        ciData.setCiInfoList(ciInfoList);
        ciData.setCiCodes(errCiCodes);
        return ciData;
    }

    private ReleaseValidResponse.CiAttrInfo validCiAttr(ESCIInfo ciInfo, Map<String, ESCIInfo> ciMap, Map<Long, CcCiClassInfo> classMap, String entityName){
        List<CcCiAttrDef> defList = classMap.get(ciInfo.getClassId()).getAttrDefs();
        Map<String, Integer> checkResult = CheckAttrUtil.validateAttrValType(defList, EamUtil.coverToAttrs(ciInfo.getAttrs()));
        if (BinaryUtils.isEmpty(checkResult)) {
            return null;
        }
        ReleaseValidResponse.CiAttrInfo ciAttrInfo = new ReleaseValidResponse.CiAttrInfo();
        ciAttrInfo.setClassName(classMap.get(ciInfo.getClassId()).getCiClass().getClassName());
        String ciName = extractMessageByRegular(ciInfo.getCiLabel()).get(0).replaceAll("\"", "");
        ciName = BinaryUtils.isEmpty(entityName) ? ciName : ciName + "【" + entityName + "】";
        ciAttrInfo.setCiName(ciName);
        ArrayList<String> missAttr = new ArrayList<>();
        for (String errInfo : checkResult.keySet()) {
            List<String> strings = extractMessageByRegular(errInfo);
            if (BinaryUtils.isEmpty(strings)) {
                continue;
            }
            missAttr.addAll(strings);
        }
        String missAttrStr = StringUtils.join(missAttr, ",");
        ciAttrInfo.setMissAttr(missAttrStr);
        return ciAttrInfo;
    }

    /**
     * 使用正则表达式提取中括号中的内容
     *
     */
    public static List<String> extractMessageByRegular(String msg) {

        List<String> list = new ArrayList<>();
        final Pattern compile = Pattern.compile("(\\[[^\\]]*\\])");
        Matcher m = compile.matcher(msg);
        while (m.find()) {
            list.add(m.group().substring(1, m.group().length() - 1));
        }
        return list;
    }

    public ReleaseValidResponse checkCjDiagram(PushParams params) {
        List<String> diagramIds = params.getDiagramIds();
        List<Integer> isOpens = params.getIsOpens();
        String ownerCode = params.getOwnerCode();
        //私有库信息
        List<ESDiagram> diagramList = diagramApiClient.selectByIds(diagramIds, null, isOpens);
        if (BinaryUtils.isEmpty(diagramList) || diagramIds.size() != diagramList.size()) {
            throw new BinaryException("所要发布视图不存在");
        }
        diagramList.stream().filter(each -> BinaryUtils.isEmpty(each.getLocalVersion())).forEach(each -> each.setLocalVersion(0));
        diagramList.stream().filter(each -> BinaryUtils.isEmpty(each.getReleaseVersion())).forEach(each -> each.setReleaseVersion(0));
        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        Map<String, ESDiagram> ownerDiagramMap = diagramList.stream().filter(diagram -> Objects.equals(loginCode, diagram.getOwnerCode())).collect(Collectors.toMap(ESDiagram::getDEnergy, each -> each));
        Map<String, ESDiagram> shareDiagramMap = diagramList.stream().filter(diagram -> !Objects.equals(loginCode, diagram.getOwnerCode())).collect(Collectors.toMap(ESDiagram::getDEnergy, each -> each));
        if (ownerDiagramMap.size() > 0) {
            List<String> ownerDiagramIds = ownerDiagramMap.values().stream().map(ESDiagram::getDEnergy).collect(Collectors.toList());
            List<ESDiagram> ownerDiagram = new ArrayList<>(ownerDiagramMap.values());
            ReleaseValidResponse releaseValidResponse = handleDiagram(ownerDiagramIds, ownerDiagram, SysUtil.getCurrentUserInfo().getDomainId(), loginCode, params.getModelId());
            if (!Objects.equals(releaseValidResponse.getValidType(), ReleaseValidResponse.ValidType.PASS)) {
                return releaseValidResponse;
            }
        }
        if (shareDiagramMap.size() > 0) {
            Map<String, List<ESDiagram>> diagramMap = new HashMap<>();
            for (Map.Entry<String, ESDiagram> entry : shareDiagramMap.entrySet()) {
                ESDiagram diagram = entry.getValue();
                List<ESDiagram> esDiagramList = diagramMap.get(diagram.getOwnerCode());
                if (!CollectionUtils.isEmpty(esDiagramList)) {
                    esDiagramList.add(diagram);
                } else {
                    esDiagramList = new ArrayList<>();
                    esDiagramList.add(diagram);
                    diagramMap.put(diagram.getOwnerCode(), esDiagramList);
                }
            }
            for (Map.Entry<String, List<ESDiagram>> entry : diagramMap.entrySet()) {
                List<ESDiagram> shareDiagram = entry.getValue();
                List<String> shareDiagramIds = shareDiagram.stream().map(ESDiagram::getDEnergy).collect(Collectors.toList());
                ReleaseValidResponse response = handleDiagram(shareDiagramIds, shareDiagram, shareDiagram.get(0).getDomainId(), entry.getKey(), params.getModelId());
                if (!Objects.equals(response.getValidType(), ReleaseValidResponse.ValidType.PASS)) {
                    return response;
                }
            }
        }
        ReleaseValidResponse response = new ReleaseValidResponse();
        response.setResultCode(1);
        response.setValidType(ReleaseValidResponse.ValidType.PASS);
        return response;
    }
    public Map<String,String> findMapperInDiagramNode(List<Long> diagramIds, List<String> freeCiCodes){
        List<ESDiagramNode> nodes = diagramApiClient.selectNodeByDiagramIds(diagramIds);
        if(BinaryUtils.isEmpty(nodes)){
            return Collections.emptyMap();
        }
        Set<String> ciCodes = DataModelDiagramUtil.getNodeCiCode(nodes);
        if(!BinaryUtils.isEmpty(freeCiCodes)){
            ciCodes.addAll(freeCiCodes);
        }
        if(BinaryUtils.isEmpty(ciCodes)){
            return Collections.emptyMap();
        }
        ESCISearchBean bean = new ESCISearchBean();
        bean.setPageNum(1);
        bean.setPageSize(ciCodes.size());
        bean.setDomainId(SysUtil.getCurrentUserInfo().getDomainId());
        bean.setCiCodes(new ArrayList<>(ciCodes));
        bean.setOwnerCode(SysUtil.getCurrentUserInfo().getLoginCode());
        bean.setStates(Lists.newArrayList(CIState.CREATE_COMPLETE, CIState.CREATE_PENDING));
        Page<ESCIInfo> ciPage = ciSwitchSvc.searchESCIByBean(bean, LibType.PRIVATE);
        if(BinaryUtils.isEmpty(ciPage.getData())){
            return Collections.emptyMap();
        }
        List<String> ciPrimaryKeys = ciPage.getData().stream().map(ESCIInfo::getCiPrimaryKey).collect(Collectors.toList());
        ESCISearchBean search = new ESCISearchBean();
        search.setPageNum(1);
        search.setPageSize(ciPrimaryKeys.size());
        search.setDomainId(SysUtil.getCurrentUserInfo().getDomainId());
        search.setCiPrimaryKeys(ciPrimaryKeys);
        Page<ESCIInfo> ciReleasePage = ciSwitchSvc.searchESCIByBean(search, LibType.DESIGN);
        if(BinaryUtils.isEmpty(ciReleasePage.getData())){
            return Collections.emptyMap();
        }
        Map<String,String> assetMapper = new HashMap<>(16);
        Map<String, ESCIInfo> privateMap = ciPage.getData().stream().collect(Collectors.toMap(ESCIInfo::getCiPrimaryKey, each -> each, (k1, k2) -> k2));
        for (ESCIInfo releaseCi : ciReleasePage.getData()) {
            ESCIInfo privateCi = privateMap.get(releaseCi.getCiPrimaryKey());
            if(BinaryUtils.isEmpty(privateCi)){
                continue;
            }
            if(privateCi.getCiCode().equals(releaseCi.getCiCode())){
                continue;
            }
            assetMapper.put(privateCi.getCiCode(), releaseCi.getCiCode());
        }
        return assetMapper;
    }

    public void processCatalog(Map<String,String> assetMapper, String ownerCode){
        if(BinaryUtils.isEmpty(assetMapper)){
            return;
        }
        List<EamCategory> categories = diagramCategorySvc.selectListByCiCodes(null, new ArrayList<>(assetMapper.keySet()), ownerCode, LibType.PRIVATE);
        List<EamCategory> categoryList = new ArrayList<>(categories.size());
        for (EamCategory category : categories) {
            String newAssetCode = assetMapper.get(category.getCiCode());
            if(BinaryUtils.isEmpty(newAssetCode)){
                continue;
            }
            if(newAssetCode.equals(category.getCiCode())){
                continue;
            }
            category.setCiCode(newAssetCode);
            categoryList.add(category);
        }
        diagramCategorySvc.saveOrUpdateList(categoryList, LibType.PRIVATE);
    }

    private ReleaseValidResponse handleDiagram(List<String> diagramIds, List<ESDiagram> diagramList, Long domainId, String loginCode, Long modelId) {
        ReleaseValidResponse response = new ReleaseValidResponse();
        List<EamCategory> categories = diagramCategorySvc.selectByDiagramIdList(diagramIds, loginCode, LibType.PRIVATE);
        Map<String, Long> diagramIdMap = diagramList.stream().collect(Collectors.toMap(ESDiagram::getDEnergy, ESDiagram::getId, (k1, k2) -> k1));
        HashMap<Long, Integer> diagramIdMapLvl = MapUtil.newHashMap();
        for (EamCategory category : categories) {
            diagramIdMapLvl.put(diagramIdMap.get(category.getDiagramId()), category.getDirLvl());
        }
        //未发布视图目录
        List<String> freeCiCodes = categories.stream().map(EamCategory::getCiCode).distinct().collect(Collectors.toList());
        Map<Long, String> diagramNameMap = diagramList.stream().collect(Collectors.toMap(ESDiagram::getId, ESDiagram::getName, (k1, k2) -> k1));
        List<Long> diagramIdList = diagramList.stream().map(ESDiagram::getId).collect(Collectors.toList());
        List<ESDiagramNode> nodes = diagramApiClient.selectNodeByDiagramIds(diagramIdList);
        Map<Long, Set<String>> diagramCiCodeMap = new HashMap<>();
        Set<String> assetCodes = new HashSet<>();
        for (ESDiagramNode node : nodes) {
            if (BinaryUtils.isEmpty(node.getCiCode())) {
                continue;
            }
            assetCodes.add(node.getCiCode());
            Set<String> ciCodes = diagramCiCodeMap.computeIfAbsent(node.getDiagramId(), k -> new HashSet<>());
            ciCodes.add(node.getCiCode());
        }

        List<Long> diagramIdSort = new ArrayList<>(diagramCiCodeMap.keySet());
        diagramIdSort.sort((o1, o2) -> {
            if (BinaryUtils.isEmpty(diagramIdMapLvl) || BinaryUtils.isEmpty(diagramIdMapLvl.get(o1)) || BinaryUtils.isEmpty(diagramIdMapLvl.get(o2))) {
                return 0;
            }
            return diagramIdMapLvl.get(o1) - diagramIdMapLvl.get(o2);
        });

        assetCodes.addAll(freeCiCodes);
        if (CollectionUtils.isNotEmpty(assetCodes)) {
            ESCISearchBean bean = new ESCISearchBean();
            bean.setPageNum(1);
            bean.setPageSize(assetCodes.size());
            bean.setDomainId(domainId);
            bean.setCiCodes(new ArrayList<>(assetCodes));
            bean.setOwnerCode(loginCode);
            Page<ESCIInfo> ciPage = ciSwitchSvc.searchESCIByBean(bean, LibType.PRIVATE);
            if (!BinaryUtils.isEmpty(ciPage.getData())) {
                List<Long> classIds = ciPage.getData().stream().map(ESCIInfo::getClassId).distinct().collect(Collectors.toList());
                CCcCiClass cdt = new CCcCiClass();
                cdt.setIds(classIds.toArray(new Long[0]));
                List<CcCiClassInfo> ccCiClassInfos = ciClassApiSvc.queryClassByCdt(cdt);
                Map<Long, CcCiClassInfo> classMap = ccCiClassInfos.stream().collect(Collectors.toMap(each -> each.getCiClass().getId(), each -> each, (k1, k2) -> k2));
                Map<String, Map<String, Integer>> errAll = new HashMap<>();
                Map<String, String> assetMap = new HashMap<>();
                //校验属性
                for (ESCIInfo ci : ciPage.getData()) {
                    List<CcCiAttrDef> defs = classMap.get(ci.getClassId()).getAttrDefs();
                    Map<String, Integer> checkResult = CheckAttrUtil.validateAttrValType(defs, EamUtil.coverToAttrs(ci.getAttrs()));
                    errAll.put(ci.getCiCode(), checkResult);
                    assetMap.put(ci.getCiCode(), classMap.get(ci.getClassId()).getCiClass().getClassName() + ":" + ci.getCiLabel());
                }
                if (!BinaryUtils.isEmpty(errAll)) {
                    //对象校验CI
                    List<ReleaseValidResponse.CiInfo> ciInfoList = new ArrayList<>();
                    ArrayList<String> errCiCodes = new ArrayList<>();
                    for (Long diagramId : diagramIdSort) {
                        Set<String> ciCodes = diagramCiCodeMap.get(diagramId);
                        String diagramName = diagramNameMap.get(diagramId);
//                    List<String> errEachList = new ArrayList<>();
                        List<ReleaseValidResponse.CiAttrInfo> checkData = new ArrayList<>();
                        for (String ciCode : ciCodes) {
                            Map<String, Integer> errMap = errAll.remove(ciCode);
                            if (!BinaryUtils.isEmpty(errMap)) {
                                //单个对象
                                errCiCodes.add(ciCode);
                                ReleaseValidResponse.CiAttrInfo ciAttrInfo = new ReleaseValidResponse.CiAttrInfo();
                                String[] split = assetMap.get(ciCode).split(":");
                                ciAttrInfo.setClassName(split[0]);
                                ciAttrInfo.setCiName(extractMessageByRegular(assetMap.get(ciCode)).get(0).replaceAll("\"", ""));
                                ArrayList<String> missAttr = new ArrayList<>();
                                for (String errInfo : errMap.keySet()) {
                                    List<String> strings = extractMessageByRegular(errInfo);
                                    if (CollectionUtils.isNotEmpty(strings)) {
                                        missAttr.addAll(strings);
                                    }
                                }
                                String missAttrStr = StringUtils.join(missAttr, ",");
                                ciAttrInfo.setMissAttr(missAttrStr);
                                checkData.add(ciAttrInfo);
                            }
                        }
                        if (CollectionUtils.isNotEmpty(checkData)) {
                            //每张视图对应校验信息
                            ReleaseValidResponse.CiInfo ciInfo = new ReleaseValidResponse.CiInfo();
                            ciInfo.setCheckData(checkData);
                            ciInfo.setDiagramName(diagramName);
                            ciInfoList.add(ciInfo);

                        }
                    }

                    if (CollectionUtils.isNotEmpty(ciInfoList)) {
                        ReleaseValidResponse.CiData ciData = new ReleaseValidResponse.CiData();
                        ciData.setCiInfoList(ciInfoList);
                        ciData.setCiCodes(errCiCodes);
                        response.setResultCode(0);
                        response.setValidType(ReleaseValidResponse.ValidType.CI_DATA);
                        response.setResponseData(ciData);
                        return response;
                    }
                }
            }
        }
        response.setResultCode(1);
        response.setValidType(ReleaseValidResponse.ValidType.PASS);
        return response;
    }


    /**
     * 根据视图ID 将当前发布视图内的CI/RLT数据版本号记录到视图节点上
     * @param dEnergys 当前已发布的设计库视图IDS
     * @return
     */
    public Boolean bindVersionNoByDiagramId(List<String> dEnergys) {
        // 根据ID查询视图node/link节点信息
        List<ESDiagramNode> nodeList = esDiagramNodeDao.getListByQuery(QueryBuilders.termsQuery("dEnergy.keyword", dEnergys));

        List<String> ciCodeList = new ArrayList<>();
        List<ESDiagramNode> updateNodeList = new ArrayList<>();     // node节点包含数据 需要绑定version
        nodeList.forEach(node -> {
            if (!BinaryUtils.isEmpty(node.getCiCode())) {
                ciCodeList.add(node.getCiCode());
                updateNodeList.add(node);
            }
        });
        if (!CollectionUtils.isEmpty(ciCodeList)) {
            // 直接在历史库中获取CI最新版本号
            Map<String, Long> ciCodeMaxVersion = iamsESCIHistoryDesignSvc.getCICodeMaxVersion(ciCodeList);

            // node节点绑定设计库CI的version
            for (ESDiagramNode updateNode : updateNodeList) {
                // 兼容一下异常数据
                if (!BinaryUtils.isEmpty(ciCodeMaxVersion.get(updateNode.getCiCode()))) {
                    updateNode.setVersion(ciCodeMaxVersion.get(updateNode.getCiCode()));
                    log.info("############## node 节点版本信息绑定成功 nodeId:【{}】 ciCode:【{}】 versionNo:【{}】##############", updateNode.getId(), updateNode.getCiCode(), ciCodeMaxVersion.get(updateNode.getCiCode()));
                } else {
                    log.info("############## node 在绑定 ci 版本号时未查询到设计库对应数据 nodeId=" + updateNode.getId() + "##############");
                }
            }
            esDiagramNodeDao.saveOrUpdateBatch(updateNodeList);
        }


        // 关系版本刷新逻辑同CI一致
        List<ESDiagramLink> linkList = esDiagramLinkDao.getListByQuery(QueryBuilders.termsQuery("dEnergy.keyword", dEnergys));

        List<String> uniqueCodeList = new ArrayList<>();
        List<ESDiagramLink> updateLinkList = new ArrayList<>();
        linkList.forEach(link -> {
            if (!BinaryUtils.isEmpty(link.getUniqueCode())) {
                uniqueCodeList.add(link.getUniqueCode());
                updateLinkList.add(link);
            }
        });
        if (!CollectionUtils.isEmpty(uniqueCodeList)) {

            Map<String, Long> uniqueCodeMaxVersion = iamsESCIRltInfoHistoryDesignSvc.getUniqueCodeMaxVersion(uniqueCodeList);
            for (ESDiagramLink updateLink : updateLinkList) {
                if (!BinaryUtils.isEmpty(uniqueCodeMaxVersion.get(updateLink.getUniqueCode()))) {
                    updateLink.setVersion(uniqueCodeMaxVersion.get(updateLink.getUniqueCode()));
                    log.info("############## link 节点版本信息绑定成功 linkId:【{}】 unquieCode:【{}】 versionNo:【{}】##############", updateLink.getId(), updateLink.getUniqueCode(), uniqueCodeMaxVersion.get(updateLink.getUniqueCode()));
                } else {
                    log.info("############## link 在绑定 rlt 版本号时未查询到设计库对应数据 linkId=" + updateLink.getId() + "##############");
                }
            }
            esDiagramLinkDao.saveOrUpdateBatch(updateLinkList);
        }
        return true;
    }
}
